package log

import (
	"context"
	"fmt"
	"grpc.getaway.adminspro.padmins.com/pkg/libs/utils"
)

type Logger interface {
	Debug(args ...interface{})
	Info(args ...interface{})
	Warning(args ...interface{})
	Error(args ...interface{})
	Print(args ...interface{})
	Fatal(args ...interface{})
}

type LoggerT struct {
	logConfig *LogConfig
	prefix    string
	ctx       context.Context
}

func (logger *LoggerT) output(level Level, args ...interface{}) {
	l := len(args)
	if logger.IsLevelEnabled(level) && l > 0 {
		lName, ok := LevelName[level]
		if !ok {
			lName = "UNKNOWN"
		}

		record := &Record{
			Date:   utils.Date(logger.logConfig.dateLayout),
			Prefix: logger.prefix,
			Msg:    fmt.Sprintf("%v", args[0]),
			Extra:  map[string]interface{}{},
			Level:  lName,
		}

		if l > 1 {
			record.Args = args[1:]
		}

		for _, processor := range logger.logConfig.processors {
			processor(logger.ctx, record)
		}
		if logger.logConfig.w != nil {
			w, err := logger.logConfig.w(logger.ctx)
			if err != nil {
				panic(err)
			}
			logger.logConfig.m.SetOutput(w)
		}
		logger.logConfig.m.Output(2, logger.logConfig.formatter(logger.ctx, record))
	}
}

func (logger *LoggerT) Debug(args ...interface{}) {
	logger.output(DebugLevel, args...)
}

func (logger *LoggerT) Info(args ...interface{}) {
	logger.output(InfoLevel, args...)
}

func (logger *LoggerT) Warning(args ...interface{}) {
	logger.output(WarnLevel, args...)
}

func (logger *LoggerT) Error(args ...interface{}) {
	logger.output(ErrorLevel, args...)
}

func (logger *LoggerT) Fatal(args ...interface{}) {
	logger.output(FatalLevel, args...)
}

func (logger *LoggerT) Print(args ...interface{}) {
	logger.output(InfoLevel, args...)
}

func (logger *LoggerT) IsLevelEnabled(l Level) bool {
	return logger.logConfig.l >= l
}

func NewLogger(ctx context.Context, prefix string, logConfig *LogConfig) Logger {
	return &LoggerT{
		logConfig: logConfig,
		ctx:       ctx,
		prefix:    prefix,
	}
}
